package me.luraframework.auth.system.service;

import lombok.RequiredArgsConstructor;
import me.luraframework.auth.exception.AuthErrorCode;
import me.luraframework.auth.security.OnlineService;
import me.luraframework.auth.system.domain.User;
import me.luraframework.auth.system.repository.UserRepository;
import me.luraframework.auth.system.service.dto.RoleSmallDto;
import me.luraframework.auth.system.service.dto.UserDto;
import me.luraframework.auth.system.service.dto.UserQueryCriteria;
import me.luraframework.auth.system.service.mapstruct.UserMapper;
import me.luraframework.auth.util.ValidationUtil;
import me.luraframework.commons.exception.AppException;
import me.luraframework.commons.model.PageDto;
import me.luraframework.db.criteria.QueryHelper;
import me.luraframework.db.util.PageUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "user")
public class UserService {

    private final UserRepository userRepository;
    private final UserMapper userMapper;
    private final OnlineService onlineUserService;

    public PageDto<UserDto> queryAll(UserQueryCriteria criteria, Pageable pageable) {
        Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelper.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtils.toPageDto(page.map(userMapper::toDto));
    }

    public List<UserDto> queryAll(UserQueryCriteria criteria) {
        List<User> users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelper.getPredicate(root, criteria, criteriaBuilder));
        return userMapper.toDto(users);
    }

    @Cacheable(key = "'id:' + #p0")
    @Transactional(rollbackFor = Exception.class)
    public UserDto findById(long id) {
        User user = userRepository.findById(id).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", id);
        return userMapper.toDto(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public void create(User resources) {
        if (userRepository.findByUsername(resources.getUsername()) != null) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }
        if (userRepository.findByEmail(resources.getEmail()) != null) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }
        if (userRepository.findByPhone(resources.getPhone()) != null) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }
        userRepository.save(resources);
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(User resources) throws Exception {
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", resources.getId());
        User user1 = userRepository.findByUsername(resources.getUsername());
        User user2 = userRepository.findByEmail(resources.getEmail());
        User user3 = userRepository.findByPhone(resources.getPhone());
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }
        if (user2 != null && !user.getId().equals(user2.getId())) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }
        if (user3 != null && !user.getId().equals(user3.getId())) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }

        user.setUsername(resources.getUsername());
        user.setEmail(resources.getEmail());
        user.setEnabled(resources.getEnabled());
        user.setRoles(resources.getRoles());
        user.setDept(resources.getDept());
        user.setPhone(resources.getPhone());
        user.setNickName(resources.getNickName());
        user.setGender(resources.getGender());
        userRepository.save(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateCenter(User resources) {
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        User user1 = userRepository.findByPhone(resources.getPhone());
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        }
        user.setNickName(resources.getNickName());
        user.setPhone(resources.getPhone());
        user.setGender(resources.getGender());
        userRepository.save(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        for (Long id : ids) {
            // 清理缓存
            UserDto user = findById(id);
        }
        userRepository.deleteAllByIdIn(ids);
    }

    public UserDto findByName(String userName) {
        User user = userRepository.findByUsername(userName);
        if (user == null) {
            throw new AppException(AuthErrorCode.ENTITY_ALREADY_EXIST);
        } else {
            return userMapper.toDto(user);
        }
    }



    @Transactional(rollbackFor = Exception.class)
    public void updateEmail(String username, String email) {
        userRepository.updateEmail(username, email);
    }

    public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (UserDto userDTO : queryAll) {
            List<String> roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList());
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("用户名", userDTO.getUsername());
            map.put("角色", roles);
            map.put("部门", userDTO.getDept().getName());
            map.put("邮箱", userDTO.getEmail());
            map.put("状态", userDTO.getEnabled() ? "启用" : "禁用");
            map.put("手机号码", userDTO.getPhone());
            map.put("修改密码的时间", userDTO.getPwdResetTime());
            map.put("创建日期", userDTO.getCreateTime());
            list.add(map);
        }
        // FileUtil.downloadExcel(list, response);
    }


}
